package edu.pku.se.chocolate.solver;

import java.io.IOException;

import org.xml.sax.SAXException;

import edu.pku.se.chocolate.datastructure.RequstMessageResponse;
import edu.pku.se.chocolate.datastructure.Tag;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.IBinder;
import android.util.Log;

/**
 * Service to fetch message in background. It tries to keeps only one task
 * on-the-fly. i.e. if a new task is submitted when an older one hasn't 
 * finished, the older one will be canceled and the new one is scheduled to
 * run. If this service is killed, it will not automatically restart.
 * For using it, one can consider using static method submitTask or pass 
 * well-format Intent to start this service.
 * @author easyhard
 */
public class FetchMessageService extends Service {
	
	private class Param 
	{
		Tag tag;
		int ID, N;
	}

	public static final String TAG = "FetchMessageService";
	
	private class FetchMessageTask extends AsyncTask<Param, Integer, RequstMessageResponse> {
		int startID;
		FetchMessageService parent;
		
		public FetchMessageTask(int startID, FetchMessageService parent) {
			super();
			this.startID = startID;
			this.parent = parent;
		}
		
		@Override
		protected RequstMessageResponse doInBackground(Param... params) {
			MessageFetcher mf = new MessageFetcher();
			if (this.isCancelled())
				return null;
			RequstMessageResponse result = null;
			try {
				result = mf.getMessage(params[0].tag, params[0].ID, params[0].N);
			} catch (IOException e) {
				e.printStackTrace();
				Log.i(TAG, e.toString());
			} catch (SAXException e) {
				e.printStackTrace();
				Log.i(TAG, e.toString());
			} catch (Exception e) {
				e.printStackTrace();
				Log.i(TAG, e.toString());
			}
			if (this.isCancelled())
				return null;
			return result;
		}
		
	     @Override
		protected void onPostExecute(RequstMessageResponse result) {
	    	 if (result != null) {
	    		 Log.i(TAG, "submitting Message number: " + result.messages.size());
	    		ChocolateSolver.getInstance().setResponseMessage(result);
	    	 }
	    	 else {
	    		 Log.i(TAG, "hitting a null on PostExecut(Fetch Message)");
	    	 }
	    	 parent.stopSelf(startID);
	     }		
		
	     @Override
	     protected void onCancelled () {
	    	 Log.i(TAG, "AsyncTask got cancelled");
	     }
	}
	
	FetchMessageTask fmTask = null;
	
	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
	

	@Override
	public void onCreate() {
		
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.i(TAG, "onStartCommand");
		if (fmTask != null)
			fmTask.cancel(true);
		Param param = new Param();
		param.ID = intent.getIntExtra("ID", -1);
		assert(param.ID != -1);
		param.N = intent.getIntExtra("N", -1);
		assert(param.N != -1);
		param.tag = (Tag) intent.getSerializableExtra("tag");
		
		fmTask = new FetchMessageTask(startId, this);
		fmTask.execute(param);
		// If we get killed, do not need to restart
		return START_NOT_STICKY;
	}
	
	/**
	 * This is a warp of this Service's onStartCommand. If you 
	 * don't want to care about construct Intent, you can use
	 * this to just pass the right param. It's recommended to
	 * use it method rather than directly pass Intent.
	 * For functionality this service provides, 
	 * see class FetchMessageService::onStartCommnad
	 * @param caller
	 * Context of the caller. Use to construct the intent and involve
	 * the service
	 * @param tag
	 * the tag you want to fetch message
	 * @param ID
	 * mark-down ID. Fetched messages's ID will not larger than it
	 * @param N
	 * number of messages requesting.
	 */
	static public void submitTask(Context caller, Tag tag, int ID, int N) {
		Intent d = null;
		try {
			d.clone();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		Intent intent = new Intent(caller, FetchMessageService.class);
		intent.putExtra("ID", ID);
		intent.putExtra("N", N);
		intent.putExtra("tag", tag);
		caller.startService(intent);
	}
}
